/*
   Copyright 2009 Bloo. All Rights Reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
package org.youtensils.www.client.widgets;

import java.util.ArrayList;

import org.youtensils.www.client.data.youtube.YouTubeDataListener;
import org.youtensils.www.client.data.youtube.YouTubeLoader;
import org.youtensils.www.client.data.youtube.YouTubeMovie;
import org.youtensils.www.client.data.youtube.YouTubeSearchFilter;
import org.youtensils.www.client.data.youtube.YouTubeSearchResults;
import org.youtensils.www.client.data.youtube.YouTubeSearchSortBy;
import org.youtensils.www.client.events.MovieActionEvent;
import org.youtensils.www.client.events.MovieActionListener;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.HorizontalSplitPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * A widget that displays paged search results.
 * @author Bobby Soares
 */
public class SearchResultsPanel extends Composite implements ClickHandler, YouTubeDataListener, MovieActionListener {
	private ArrayList<MovieActionListener> actionListeners;
	private String searchQuery, author;
	private YouTubeLoader tubeLoader;
	private HorizontalSplitPanel contentPane;
	private VerticalPanel leftPanel, rightPanel;
	private int currentPage = 0, pageSize = 10;
	private HorizontalPanel topPagePanel, bottomPagePanel;
	
	/**
	 * A constructor specifying the text to search and the author to which the search should be restricted.
	 * @param searchQuery the text to search for
	 * @param author the author to which the search should be restricted
	 */
	public SearchResultsPanel(String searchQuery, String author){
		this.actionListeners = new ArrayList<MovieActionListener>();
		this.searchQuery = searchQuery;
		this.author = author;
		this.tubeLoader = new YouTubeLoader();
		this.tubeLoader.addListener(this);
    	this.leftPanel = new VerticalPanel();
    	this.leftPanel.setWidth("100%");
    	this.leftPanel.setStylePrimaryName("gwt-SearchResults-Left");
    	this.leftPanel.add(new HTML("Searching..."));
    	this.rightPanel = new VerticalPanel();
    	this.rightPanel.setWidth("100%");
    	this.rightPanel.setHeight("100%");
    	this.rightPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
    	this.rightPanel.setVerticalAlignment(VerticalPanel.ALIGN_MIDDLE);
    	this.rightPanel.setStylePrimaryName("gwt-SearchResults-Right");
		this.contentPane = new HorizontalSplitPanel();
    	this.contentPane.setWidth("100%");
    	this.contentPane.setHeight("100%");
    	this.contentPane.setSplitPosition("100%");
    	this.contentPane.setLeftWidget(this.leftPanel);
    	this.contentPane.setRightWidget(this.rightPanel);
		initWidget(this.contentPane);
    	setStyleName("gwt-SearchResults");
	}
	
	/**
	 * Loads the search results.
	 */
	public void load(){
		this.tubeLoader.searchVideos(this.searchQuery, "", this.author,
				YouTubeSearchSortBy.RELEVANCE,
				YouTubeSearchFilter.NONE,
				(this.currentPage*this.pageSize)+1, this.pageSize);
	}
	
	/**
	 * Adds a movie action event listener
	 * @param listener the event listener to register
	 */
	public void addActionListener(MovieActionListener listener){
		actionListeners.add(listener);
	}
	
	public void onSearchResults(YouTubeSearchResults results) {
		this.leftPanel.clear();
		this.leftPanel.getElement().setScrollTop(0);
		YouTubeMovie[] entries = results.getEntries();
		this.leftPanel.clear();
		if(entries.length == 0){
			this.leftPanel.add(new HTML("No matches found."));
			return;
		}
		if(this.rightPanel.getWidgetCount() == 0){
	    YouTubeMovie mov = results.getEntries()[0];
		  this.rightPanel.add(new HTML("<div class=\"gwt-VideoHeader\">" + mov.getTitle() + "</div>"));
			this.rightPanel.add(new HTML(mov.getEmbedHtml()));
		}
		this.topPagePanel = this.makeResultsPager(results);
		this.leftPanel.add(this.topPagePanel);
		for(int i=0; i<entries.length; i++){
			YouTubeMovie mov = entries[i];
			SearchResultsEntryPanel entry = new SearchResultsEntryPanel(mov, this.searchQuery);
			entry.setAlternating(i%2 == 0);
			entry.addActionListener(this);
			this.leftPanel.add(entry);
		}
		this.bottomPagePanel = this.makeResultsPager(results);
		this.leftPanel.add(this.bottomPagePanel);
	}
	
	public void onAction(MovieActionEvent e, Object sender) {
		YouTubeMovie mov = e.getMovie();
		if(e.getAction().equals("play")){
			//handle play events
			this.contentPane.setSplitPosition("50%");
			this.rightPanel.clear();
      this.rightPanel.add(new HTML("<div class=\"gwt-VideoHeader\">" + mov.getTitle() + "</div>"));
			this.rightPanel.add(new HTML("<br />" + mov.getEmbedHtml()));
		}else{
			//let other events bubble up
			for(int i=0; i<this.actionListeners.size(); i++){
				this.actionListeners.get(i).onAction(e, this);
			}
		}
	}
	
	/**
	 * Builds a panel containing the page navigation.
	 * @param results the search results for which to build the page navigation
	 * @return a horizontal panel containing the page navigation
	 */
	private HorizontalPanel makeResultsPager(YouTubeSearchResults results){
		HorizontalPanel pagePanel =  new HorizontalPanel();
		pagePanel.setStylePrimaryName("gwt-SearchResults-PageMenu");
		pagePanel.setWidth("100%");
		
		if(results.getTotalResults() < this.pageSize) return pagePanel;
		
		HorizontalPanel main = new HorizontalPanel();
		int firstPage, lastPage, totalPages = 10, curPage = results.getPageIndex() + 1;
		firstPage = results.getPageIndex() - (int)(Math.ceil(totalPages)/2);
		if(firstPage < 1) firstPage = 1;
		lastPage = firstPage + totalPages;
		if(lastPage > results.getTotalPages()) lastPage = results.getTotalPages();
		main.setStylePrimaryName("gwt-SearchResults-PageMenu");
		
		Anchor first = new 		Anchor();
		first.setText("First");
		if(curPage < 2)
			first.getElement().setPropertyBoolean("disabled", true);
		first.addClickHandler(this);
		main.add(first);
		
		Anchor prev = new 		Anchor();
		prev.setText("Previous");
		if(curPage < 2)
			prev.getElement().setPropertyBoolean("disabled", true);
		prev.addClickHandler(this);
		main.add(prev);
		
		for(int i=firstPage; i<=lastPage; i++){
			if(i == curPage){
				HTML page = new HTML("<b>" + i + "</b>");
				main.add(page);
			}else{
				Anchor page = new Anchor();
				page.setText("" + i);
				page.addClickHandler(this);
				main.add(page);
			}
		}
		Anchor next = new Anchor();
		next.setText("Next");
		if(curPage >= results.getTotalPages())
			next.getElement().setPropertyBoolean("disabled", true);
		next.addClickHandler(this);
		main.add(next);
		
		pagePanel.add(main);
		return pagePanel;
	}
	
	/**
	 * Disables a given panel.
	 * @param panel the panel to deactivate
	 */
	private void disablePanel(HorizontalPanel panel){
		for(int i=0; i<panel.getWidgetCount(); i++){
			Widget w = panel.getWidget(i);
			w.getElement().setPropertyBoolean("disabled", true);
		}
	}

	@Override
	public void onClick(ClickEvent event) {
		Anchor link = (Anchor) event.getSource();
		if(link.getElement().getPropertyBoolean("disabled")) return;
		String label = link.getText();
		int newPage = 0;
		if(label.equalsIgnoreCase("First")){
			newPage = 0;
		}else if(label.equalsIgnoreCase("Previous")){
			newPage = this.currentPage - 1;
		}else if(label.equalsIgnoreCase("Next")){
			newPage = this.currentPage + 1;
		}else{
			newPage = Integer.parseInt(label) - 1;
		}
		this.currentPage = newPage;
		this.disablePanel(this.topPagePanel);
		this.disablePanel(this.bottomPagePanel);
		this.load();
	}
	
}
